﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Globalization;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 
    struct ItemInf
    {
        public int ID;
        public double height;
        public double bust;
        public double waist;
        public double hipline;
        public string size = new("");
        //扩展数据
        public double dExtend1;  //后三围
        public double dExtend2;  //衣长
        public double dExtend3;  //肩宽
        public double dExtend4;  //袖长
        public string sExtend5;  //备注
    }
    class displayInf
        //为了能让DataGrid直接读取数据，这里定义了接口
    {
        public string StdType { get; set; }
        public string typeY { get; set; }
        public string typeA { get; set; }
        public string typeB { get; set; }
        public string typeC { get; set; }
        public string typeD { get; set; }
        public string typeE { get; set; }
        public string typeF { get; set; }
        public string SimpleItems { get; set; }
        public string Average { get; set; }
        public string MaxMin { get; set; }

        public displayInf()
        {
            StdType = "";
            SimpleItems = "";
            Average = "";
            MaxMin = "";
        }
    }
    struct secondSortItem
    {
        public List<ItemInf> Y=new List<ItemInf>();
        public List<ItemInf> A = new List<ItemInf>();
        public List<ItemInf> B = new List<ItemInf>();
        public List<ItemInf> C = new List<ItemInf>();
        public List<ItemInf> D = new List<ItemInf>();
        public List<ItemInf> E = new List<ItemInf>();
        public List<ItemInf> F = new List<ItemInf>();
    };
    enum clickType { waistV,hiplineV, dExtend1V, dExtend2V, dExtend3V, dExtend4V}
    
    public partial class MainWindow : Window
    {
        List<ItemInf>[] sourceData=new List<ItemInf>[9];
        secondSortItem[] secondSorts=new secondSortItem[9];
        displayInf[] dispData=new displayInf[9];
        
        System.Windows.Shapes.Path pathBackground = new System.Windows.Shapes.Path();
        System.Windows.Shapes.Path pathDrawData = new System.Windows.Shapes.Path();
        double Vcalval;
        double Hcalval;
        clickType clickStatus=clickType.waistV;
        public MainWindow()
        {
            InitializeComponent();
            //初始化数据格子
            for(int i=0;i<9;i++)
            {
                sourceData[i]=new List<ItemInf>();
                dispData[i]=new displayInf();
                secondSorts[i] = new secondSortItem();
            }
            //初始化网格
            Hcalval = cavDrawing.Height / 6;
            Vcalval = cavDrawing.Width / 10;
            //初始化统计表
            dispData[0].StdType = "165/80";
            dispData[1].StdType = "170/84";
            dispData[2].StdType = "170/88";
            dispData[3].StdType = "175/92";
            dispData[4].StdType = "175/96";
            dispData[5].StdType = "180/100";
            dispData[6].StdType = "180/104";
            dispData[7].StdType = "185/108";
            dispData[8].StdType = "185/112";
            Datagrid1.ItemsSource = dispData;
            //初始化图形
            Canvas.SetTop(pathBackground, 0);
            Canvas.SetLeft(pathBackground, 0);
            pathBackground.Stroke = Brushes.BlanchedAlmond;
            pathBackground.StrokeThickness = 1;
            cavDrawing.Children.Add(pathBackground);
            Canvas.SetTop(pathDrawData, 0);
            Canvas.SetLeft(pathDrawData, 0);
            pathDrawData.Fill = new SolidColorBrush(Color.FromArgb(100, 0, 0, 0));
            pathDrawData.StrokeThickness = 0;
            cavDrawing.Children.Add(pathDrawData);

            DrawBackgound();
        }
        private void readDataFromFile(string Path)
        {
            int PtrBlock = 0; //这里记录块号，一组{}为一个块
            int readDataCount = 0;  //记录读取的条目数量
            int ItemType = 0;
            using(StreamReader Reader = new StreamReader(Path))
            {
                while (!Reader.EndOfStream && PtrBlock<9)
                {
                    string buffer = Reader.ReadLine();
                    if(buffer[0]=='{')
                        //块开始
                    {
                        while(true)  //块结束标记符
                        {
                            ItemInf readItem=new ItemInf();
                            buffer = Reader.ReadLine();
                            if (buffer[0] == '}') break;
                            if(buffer!=null)
                            {
                                //开始读入每一行数据
                                buffer += ' ';
                                ItemType = 0;
                                string sCell="";
                                foreach (char x in buffer)
                                {
                                    if(x==' ' || x=='\t')
                                    {
                                        try
                                            //如果数据转换失败这里会抛出异常
                                        {
                                            switch(ItemType)
                                            {
                                                case 0:
                                                    readItem.ID = Convert.ToInt32(sCell);
                                                    break;
                                                case 1:
                                                    readItem.height = Convert.ToDouble(sCell);
                                                    break;
                                                case 2:
                                                    readItem.bust=Convert.ToDouble(sCell);
                                                    break;
                                                case 3:
                                                    readItem.waist=Convert.ToDouble(sCell);
                                                    break;
                                                case 4:
                                                    readItem.hipline=Convert.ToDouble(sCell);
                                                    break;
                                                case 5:
                                                    readItem.size = sCell;
                                                    break;
                                                case 6:
                                                    readItem.dExtend1 = Convert.ToDouble(sCell);
                                                    break;
                                                case 7:
                                                    readItem.dExtend2 = Convert.ToDouble(sCell);
                                                    break;
                                                case 8:
                                                    readItem.dExtend3 = Convert.ToDouble(sCell);
                                                    break;
                                                case 9:
                                                    readItem.dExtend4 = Convert.ToDouble(sCell);
                                                    break;
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            MessageBox.Show("读取数据错误，单元格有误: 列号: "+ItemType.ToString()+" 行号: "+readDataCount.ToString()+" 单元格内容: "+sCell);
                                        }
                                        ItemType++;
                                        if(ItemType>10)
                                        {
                                            Debug.WriteLine("读取数据溢出: " + readDataCount);
                                            break;
                                        }
                                        
                                        sCell = "";
                                    }
                                    else
                                    {
                                        sCell += x;
                                    }
                                }
                                sourceData[PtrBlock].Add(readItem);
                                readDataCount++;
                            }
                        }
                        PtrBlock++;
                        if (PtrBlock>9)
                        {
                            Debug.WriteLine("数据块过多！");
                            return;
                        }
                    }
                }
            }
            Debug.WriteLine("读取条目数量为: " + readDataCount.ToString());
        }
        private void DrawData(List<double>[] vs)
            //绘制散点图
            //参数：vs 每个类别相关的数据集合(这里数据已被标准化)
        {
            //计算相关参数
            double[] MinVal = new double[9];
            double[] MaxVal = new double[9];
            for(int i=0;i<9;i++)
            {
                MinVal[i] = vs[i].Min();
                MaxVal[i] = vs[i].Max();
            }
            //开始绘制图形
            double Yscal = (cavDrawing.Height/2) / (Math.Max(MaxVal.Max(),Math.Abs(MinVal.Min())));  //这个是水平缩放系数
            if(double.IsNaN(Yscal)) Yscal = 1;
            GeometryGroup geoDrawData = new GeometryGroup();
            double Yoffset = MinVal.Min();
            if(double.IsNaN(Yoffset)) Yoffset = 0;
            GeometryGroup resDraw = new GeometryGroup();
            geoDrawData.Children.Clear();
            for(int i=0;i<9;i++)
            {
                foreach(double v in vs[i])
                {

                    EllipseGeometry aEG=new EllipseGeometry();
                    aEG.Center = new Point((i + 1) * Vcalval, (v - Yoffset) * Yscal);
                    aEG.RadiusX = 3;
                    aEG.RadiusY = 3;
                    geoDrawData.Children.Add(aEG);
                }
            }
            pathDrawData.Data = geoDrawData;
        }
        private void DrawBackgound()
            //这里水平10等分，垂直6等分
        {
            GeometryGroup geoDrawBackground = new GeometryGroup();
            for (int i = 0;i<10;i++)
            {
                LineGeometry line = new LineGeometry();
                line.StartPoint = new Point(Vcalval*i,0);
                line.EndPoint = new Point(Vcalval*i,cavDrawing.Height);
                geoDrawBackground.Children.Add(line);
            }
            for(int i=0;i<6;i++)
            {
                LineGeometry line = new LineGeometry();
                line.StartPoint=new Point(0,Hcalval*i);
                line.EndPoint = new Point(cavDrawing.Width, Hcalval * i);
                geoDrawBackground.Children.Add(line);
            }
            pathBackground.Data = geoDrawBackground;

            Label labTag = new Label();
            labTag.Content = "0";
            Canvas.SetTop(labTag, cavDrawing.Height / 2);
            Canvas.SetLeft(labTag, 0);
            cavDrawing.Children.Add(labTag);

            Label labTag1 = new Label();
            labTag1.Content = "1";
            Canvas.SetTop(labTag1, 0);
            Canvas.SetLeft(labTag1, 0);
            cavDrawing.Children.Add(labTag1);

            Label labTag2 = new Label();
            labTag2.Content = "-1";
            Canvas.SetTop(labTag2, cavDrawing.Height-22);
            Canvas.SetLeft(labTag2, 0);
            cavDrawing.Children.Add(labTag2);
        }
        private void Button_Click(object sender, RoutedEventArgs e)
            //打开文件按钮
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.Filter = "Text documents (.txt)|*.txt";
            dlg.Title = "打开数据文件";
            Nullable<bool> result = dlg.ShowDialog();
            if (result == true)
            {
                readDataFromFile(dlg.FileName);
                for(int i=0;i<9;i++)
                    dispData[i].SimpleItems = sourceData[i].Count.ToString();
                Datagrid1.ItemsSource = null;
                Datagrid1.ItemsSource = dispData;
                return;
            }
            else
            {
                Debug.WriteLine("文件未打开：未选择文件");
            }
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
            //处理数据按钮
        {
            List<double>[] vs = new List<double>[9];  //这个是用来单独提取ItemInf的其中一个成员数据
            for(int i=0;i<9;i++)
                vs[i]=new List<double>();
            for(int i=0;i<9; i++)
            {
                foreach(ItemInf d in sourceData[i])
                {
                    switch(clickStatus)
                    {
                        case clickType.waistV:
                            vs[i].Add(d.waist);
                            break;
                        case clickType.hiplineV:
                            vs[i].Add(d.hipline);
                            break;
                        case clickType.dExtend1V:
                            vs[i].Add(d.dExtend1);
                            break;
                        case clickType.dExtend2V:
                            vs[i].Add(d.dExtend2);
                            break;
                        case clickType.dExtend3V:
                            vs[i].Add(d.dExtend3);
                            break;
                        case clickType.dExtend4V:
                            vs[i].Add(d.dExtend4);
                            break;
                    }
                }
            }
            DrawData(dataStandard(vs));
        }
        private List<double>[] dataStandard(List<double>[] unStd)
        {
            List<double>[] vs = new List<double>[9];
            for (int i = 0; i < 9; i++)
            {
                vs[i] = new List<double>();
                double AveNumber = unStd[i].Average();
                double sumNum = 0;
                foreach(double d in unStd[i])
                {
                    sumNum += Math.Pow(d - AveNumber, 2);
                }
                double stdDeviation = Math.Sqrt(sumNum / unStd[i].Count());
                dispData[i].Average = Math.Round(AveNumber, 2).ToString();
                string s1 = Math.Round(unStd[i].Max(), 2).ToString() + '/' + Math.Round(unStd[i].Min(), 2).ToString();
                dispData[i].MaxMin = s1;
                foreach(double d in unStd[i])
                {
                    if (stdDeviation != 0)
                        vs[i].Add((double)((d - AveNumber) / stdDeviation));
                    else
                        vs[i].Add(d);
                }
                Datagrid1.ItemsSource = null;
                Datagrid1.ItemsSource = dispData;
            }
            return vs;
        }
        
        private void Button_Click_2(object sender, RoutedEventArgs e)
            //二次分类按钮
        {
            for(int i=0;i<9;i++)
            {
                foreach(var j in sourceData[i])
                {
                    if (j.size.Length != 3)
                    {
                        Debug.WriteLine("ERROR: Data.Size Length!=3");
                        continue;
                    }
                    switch (j.size[2])
                    {
                        case 'A':
                            secondSorts[i].A.Add(j);
                            break;
                        case 'B':
                            secondSorts[i].B.Add(j);
                            break;
                        case 'C':
                            secondSorts[i].C.Add(j);
                            break;
                        case 'D':
                            secondSorts[i].D.Add(j);
                            break;
                        case 'E':
                            secondSorts[i].E.Add(j);
                            break;
                        case 'F':
                            secondSorts[i].F.Add(j);
                            break;
                        case 'Y':
                            secondSorts[i].Y.Add(j);
                            break;
                        default:
                            Debug.WriteLine("ERROR: Data.Size[2]: "+j.size[2]);
                            break;
                    }
                }
                dispData[i].typeY = secondSorts[i].Y.Count().ToString();
                dispData[i].typeA = secondSorts[i].A.Count().ToString();
                dispData[i].typeB = secondSorts[i].B.Count().ToString();
                dispData[i].typeC = secondSorts[i].C.Count().ToString();
                dispData[i].typeD = secondSorts[i].D.Count().ToString();
                dispData[i].typeE = secondSorts[i].E.Count().ToString();
                dispData[i].typeF = secondSorts[i].F.Count().ToString();
            }
            Datagrid1.ItemsSource = null;
            Datagrid1.ItemsSource = dispData;
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
            //从数据库读取
            //尚未实现
        {

        }

        private void RadioButton_Click(object sender, RoutedEventArgs e)
            //选中腰围
        {
            clickStatus = clickType.waistV;
        }

        private void RadioButton_Click_1(object sender, RoutedEventArgs e)
            //选中臀围
        {
            clickStatus = clickType.hiplineV;
        }

        private void RadioButton_Click_2(object sender, RoutedEventArgs e)
            //选中后三围
        {
            clickStatus = clickType.dExtend1V;
        }
        private void RadioButton_Click_3(object sender, RoutedEventArgs e)
            //选中衣长
        {
            clickStatus = clickType.dExtend2V;
        }

        private void RadioButton_Click_4(object sender, RoutedEventArgs e)
            //选中肩宽
        {
            clickStatus = clickType.dExtend3V;
        }

        private void RadioButton_Click_5(object sender, RoutedEventArgs e)
            //选中袖长
        {
            clickStatus = clickType.dExtend4V;
        }

        private void Button_Click_4(object sender, RoutedEventArgs e)
            //导出二次分类结果
            //二次分类按体型分类
        {
            using(StreamWriter sw = new StreamWriter("二次分类结果.txt"))
            {
                for(int i=0;i<9;i++)
                {
                    foreach(var j in secondSorts[i].Y)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'Y';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].A)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'A';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].B)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'B';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].C)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'C';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].D)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'D';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].E)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'E';
                        sw.WriteLine(ots);
                    }
                    foreach (var j in secondSorts[i].F)
                    {
                        string ots = j.ID.ToString() + '\t' +
                            j.height.ToString() + '\t' +
                            j.bust.ToString() + '\t' +
                            j.waist.ToString() + '\t' +
                            j.hipline.ToString() + '\t' +
                            j.size + '\t' +
                            j.dExtend1.ToString() + '\t' +
                            j.dExtend2.ToString() + '\t' +
                            j.dExtend3.ToString() + '\t' +
                            j.dExtend4.ToString() + '\t' +
                            i.ToString() + '\t' +
                            'F';
                        sw.WriteLine(ots);
                    }
                }
            }
        }
    }
}
